home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / COMM / MSKRMSRC.ARJ / MSNDNS.C < prev    next >
C/C++ Source or Header  |  1991-10-24  |  16KB  |  577 lines

  1. /* File MSNDNS.C
  2.  * Domain name server requester
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  * Copyright (C) 1991, Trustees of Columbia University in the
  6.  *  City of New York.  Permission is granted to any individual or
  7.  *  institution to use, copy, or redistribute this software as long as
  8.  *  it is not sold for profit and this copyright notice is retained.
  9.  *
  10.  * Original version created by Erick Engelke of the University of
  11.  *  Waterloo, Waterloo, Ontario, Canada.
  12.  * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik, 
  13.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
  14.  *
  15.  * Last edit
  16.  * 6 Sept 1991
  17.  *
  18.  * Originally based on NCSA Telnet
  19.  *
  20.  */
  21.  
  22. #include "msntcp.h"
  23. #include "msnlib.h"
  24.  
  25. byte *def_domain;
  26. byte *loc_domain = NULL;
  27. /* current subname to be used by domain system */
  28.  
  29. longword def_nameservers[ MAX_NAMESERVERS ];
  30. int last_nameserver;
  31.  
  32. static udp_Socket *dom_sock;
  33.  
  34. #define DOMSIZE 512         /* maximum domain message size to mess with */
  35.  
  36. /*
  37.  *  Header for the DOMAIN queries
  38.  *  ALL OF THESE ARE BYTE SWAPPED QUANTITIES!
  39.  */
  40. struct dhead {
  41.     word    ident,        /* unique identifier */
  42.         flags,
  43.         qdcount,    /* question section, # of entries */
  44.         ancount,    /* answers, how many */
  45.         nscount,    /* count of name server Respsonse Records */
  46.         arcount;    /* number of "additional" records */
  47. };
  48.  
  49. /*
  50.  *  flag masks for the flags field of the DOMAIN header
  51.  */
  52. #define DQR        0x8000    /* query = 0, response = 1 */
  53. #define DOPCODE        0x7100    /* opcode, see below */
  54. #define DAA        0x0400    /* Authoritative answer */
  55. #define DTC        0x0200    /* Truncation, response was cut off at 512 */
  56. #define DRD        0x0100    /* Recursion desired */
  57. #define DRA        0x0080    /* Recursion available */
  58. #define DRCODE        0x000F    /* response code, see below */
  59.  
  60. /* opcode possible values: */
  61. #define DOPQUERY    0    /* a standard query */
  62. #define DOPIQ        1    /* an inverse query */
  63. #define DOPCQM        2    /* a completion query, multiple reply */
  64. #define DOPCQU        3         /* a completion query, single reply */
  65. /* the rest reserved for future */
  66.  
  67. /* legal response codes: */
  68. #define DROK    0        /* okay response */
  69. #define DRFORM    1        /* format error */
  70. #define DRFAIL    2        /* their problem, server failed */
  71. #define DRNAME    3        /* name error, we know name doesn't exist */
  72. #define DRNOPE    4        /* no can do request */
  73. #define DRNOWAY    5        /* name server refusing to do request */
  74.  
  75. #define DTYPEA        1    /* host address resource record (RR) */
  76. #define DTYPEPTR    12    /* a domain name ptr */
  77.  
  78. #define DIN        1    /* ARPA internet class */
  79. #define DWILD        255    /* wildcard for several classifications */
  80.  
  81. /*
  82.  *  a resource record is made up of a compressed domain name followed by
  83.  *  this structure.  All of these ints need to be byteswapped before use.
  84.  */
  85. struct rrpart {
  86.     word       rtype,        /* resource record type = DTYPEA */
  87.         rclass;        /* RR class = DIN */
  88.     longword    ttl;        /* time-to-live, changed to 32 bits */
  89.     word    rdlength;    /* length of next field */
  90.     byte     rdata[DOMSIZE];    /* data field */
  91. };
  92.  
  93. /*
  94.  *  data for domain name lookup
  95.  */
  96. static struct useek {
  97.     struct dhead h;
  98.     byte         x[DOMSIZE];
  99. } *question;
  100.  
  101. static void
  102. qinit() {
  103.     question->h.flags = intel16(DRD);
  104.     question->h.qdcount = intel16(1);
  105.     question->h.ancount = 0;
  106.     question->h.nscount = 0;
  107.     question->h.arcount = 0;
  108. }
  109.  
  110. int 
  111. add_server(int *counter, int max, longword *array, longword value)
  112. {
  113.     if (array == NULL) return (0);            /* failure */
  114.     if (value && (*counter < max))
  115.         array[ (*counter)++ ] = value;
  116.     return (1);
  117. }
  118.  
  119. /*********************************************************************/
  120. /*  packdom
  121.  *   pack a regular text string into a packed domain name, suitable
  122.  *   for the name server.
  123.  *
  124.  *   returns length
  125. */
  126. static int
  127. packdom(dst, src) byte *src, *dst; {
  128.     register byte *p, *q;
  129.     byte *savedst;
  130.     int i, dotflag, defflag;
  131.  
  132.     if (dst == NULL || src == NULL) return (0);        /* failure */
  133.     dotflag = defflag = 0;
  134.     p = src;
  135.     savedst = dst;
  136.  
  137.     do {            /* copy whole string */
  138.     *dst = 0;
  139.     q = dst + 1;
  140.     while (*p && (*p != '.'))
  141.         *q++ = *p++;
  142.  
  143.     i = p - src;
  144.     if (i > 0x3f)            /* if string is too long */
  145.         return (-1);
  146.     *dst = i;            /* leading length byte */
  147.     *q = 0;
  148.  
  149.     if (*p) {            /* if a next field */
  150.         dotflag = 1;        /* say dot seen in string */
  151.         src = ++p;
  152.         dst = q;
  153.     }
  154.     else if ((dotflag == 0) && (defflag == 0) && (def_domain != NULL)) {
  155.         p = def_domain;        /* continue packing with default */
  156.         defflag = 1;        /* say using default domain ext */
  157.         src = p;
  158.         dst = q;
  159.     }
  160.     }
  161.     while (*p);
  162.     q++;
  163.     return (q - savedst);        /* length of packed string */
  164. }
  165.  
  166. /*********************************************************************/
  167. /*  unpackdom
  168.  *  Unpack a compressed domain name that we have received from another
  169.  *  host.  Handles pointers to continuation domain names -- buf is used
  170.  *  as the base for the offset of any pointer which is present.
  171.  *  returns the number of bytes at src which should be skipped over.
  172.  *  Includes the NULL terminator in its length count.
  173.  */
  174. static int
  175. unpackdom(dst, src, buf) byte *src, *dst, buf[]; {
  176.     register word i, j;
  177.     int retval;
  178.     byte *savesrc;
  179.  
  180.     if (src == NULL || dst == NULL || buf == NULL)
  181.         return (-1);    /* failure */
  182.     savesrc = src;
  183.     retval = 0;
  184.  
  185.     while (*src) {
  186.     j = *src & 0xff;            /* length byte */
  187.     while ((j & 0xC0) == 0xC0) {         /* while 14-bit pointer */
  188.         if (retval == 0)
  189.         retval = src - savesrc + 2;
  190.         src++;
  191.         src = &buf[(j & 0x3f)*256+(*src & 0xff)]; /* 14-bit pointer deref */
  192.         j = *src & 0xff;            /* new length byte */
  193.     }
  194.  
  195.     src++;                    /* assumes 6-bit count */
  196.     for (i = 0; i < (j & 0x3f); i++)
  197.         *dst++ = *src++;            /* copy counted string */
  198.     *dst++ = '.';                /* append a dot */
  199.     }
  200.     *(--dst) = 0;            /* add terminator */
  201.     src++;                /* account for terminator on src */
  202.  
  203.     if (retval == 0)
  204.     retval = src - savesrc;
  205.     return (retval);
  206. }
  207.  
  208. /*********************************************************************/
  209. /*  sendom
  210.  *   put together a domain lookup packet and send it
  211.  *   uses port 53
  212.  *    num is used as identifier
  213.  */
  214. static word
  215. sendom(s, towho, num) byte *s; longword towho; word num; {
  216.     word i,ulen;
  217.     register byte *psave;
  218.     register byte *p;
  219.  
  220.     psave = question->x;
  221.     i = packdom(question->x, s);    /* i = length of packed string */
  222.  
  223.     p = &(question->x[i]);
  224.     *p++ = 0;                /* high byte of qtype */
  225.     *p++ = DTYPEA;        /* number is < 256, so we know high byte=0 */
  226.     *p++ = 0;                /* high byte of qclass */
  227.     *p++ = DIN;                /* qtype is < 256 */
  228.  
  229.     question->h.ident = intel16(num);
  230.     ulen = sizeof(struct dhead) + (p - psave);
  231.     if (udp_open(dom_sock, 997, towho, 53, NULL) == 0)        /* failure */
  232.         return (0);                         /* fail*/
  233.  
  234.     if (sock_write(dom_sock, (byte *)question, ulen) != ulen)
  235.         return (0);                        /* fail */
  236.  
  237.     return (ulen);
  238. }
  239.  
  240. int countpaths(pathstring) byte *pathstring; {
  241.     register int count = 0;
  242.     register byte *p;
  243.  
  244.     for (p = pathstring; (*p != 0) || (*(p+1) != 0); p++)
  245.     if (*p == '.')
  246.         count++;
  247.  
  248.     return (++count);
  249. }
  250.  
  251. static byte *
  252. getpath(pathstring, whichone)
  253. byte *pathstring;        /* the path list to search */
  254. int   whichone;            /* which path to get, starts at 1 */
  255. {
  256.     register byte *retval;
  257.  
  258.     if (pathstring == NULL) return (NULL);    /* failure */
  259.  
  260.     if (whichone > countpaths(pathstring))
  261.         return (NULL);
  262.     whichone--;
  263.     for (retval = pathstring; whichone > 0; retval++)
  264.         if (*retval == '.')
  265.             whichone--;
  266.     return (retval);
  267. }
  268.  
  269. /*********************************************************************/
  270. /*  ddextract
  271.  *   extract the ip number from a response message.
  272.  *   returns the appropriate status code and if the ip number is available,
  273.  *   copies it into mip
  274.  */
  275. static longword 
  276. ddextract(qp, mip)
  277. struct useek *qp;
  278. byte *mip;
  279. {
  280.     register int i;
  281.     int j, nans, rcode;
  282.     struct rrpart *rrp;
  283.     register byte *p;
  284.     byte space[260];
  285.  
  286.     if (qp == NULL || mip == NULL) return (0);    /* failure */
  287.     memset(space, 0, sizeof(space));
  288.     nans = intel16(qp->h.ancount);        /* number of answers */
  289.     rcode = DRCODE & intel16(qp->h.flags);   /* return code for this message*/
  290.  
  291.     if (rcode != 0)
  292.     return (rcode);
  293.  
  294.     if (nans != 0 &&                /* at least one answer */
  295.         (intel16(qp->h.flags) & DQR)) {        /* response flag is set */
  296.     p = qp->x;                    /* where question starts */
  297.     if ((i = unpackdom(space,p,qp)) == -1)    /* unpack question name */
  298.         return (-1);            /* failure to unpack */
  299.  
  300.     /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  301.     p += i + 4;
  302. /*
  303.  *  at this point, there may be several answers.  We will take the first
  304.  *  one which has an IP number.  There may be other types of answers that
  305.  *  we want to support later.
  306.  */
  307.     while (nans-- > 0) {        /* look at each answer */
  308.         if ((i = unpackdom(space,p,qp)) == -1) /* answer name to unpack */
  309.             return (-1);        /* failure to unpack */
  310.         p += i;            /* account for string */
  311.         rrp = (struct rrpart *)p;    /* resource record here */
  312.  /*
  313.   *  check things which might not align on 68000 chip one byte at a time
  314.   */
  315.         if (*p == 0 && *(p+1) == DTYPEA &&     /* correct type and class */
  316.         *(p+2) == 0 && *(p+3) == DIN) {
  317.         bcopy(rrp->rdata, mip, 4);    /* save IP # */
  318.         return (0);            /* successful return */
  319.         }
  320.         bcopy(&rrp->rdlength, &j, 2);    /* 68000 alignment */
  321.         p += 10 + intel16(j);        /* length of rest of RR */
  322.     }
  323.     }
  324.     return (-1);                /* generic failed to parse */
  325. }
  326.  
  327. /*********************************************************************/
  328. /*  getdomain
  329.  *   Look at the results to see if our DOMAIN request is ready.
  330.  *   It may be a timeout, which requires another query.
  331.  */
  332.  
  333. static longword 
  334. udpdom() {
  335.     register int i,uret;
  336.     longword desired;
  337.  
  338.     uret = sock_fastread(dom_sock, (byte *)question, sizeof(struct useek));
  339.     /* this does not happen */
  340.     if (uret < 0) {
  341.     /*  netputevent(USERCLASS,DOMFAIL,-1);  */
  342.     return (-1);
  343.     }
  344.     if (uret == 0) return (0);        /* fastread failed to read */
  345.  
  346.     /* check if the necessary information was in the UDP response */
  347.     i = ddextract(question, &desired);
  348.     switch (i) {
  349.         case 3:    return (0);        /* name does not exist */
  350.         case 0: return (intel(desired)); /* we found the IP number */
  351.         case -1:return (0);        /* strange ret code from ddextract */
  352.         default:return (0);            /* dunno */
  353.     }
  354. }
  355.  
  356.  
  357. /**************************************************************************/
  358. /*  Sdomain
  359.  *   DOMAIN based name lookup
  360.  *   query a domain name server to get an IP number
  361.  *    Returns the machine number of the machine record for future reference.
  362.  *   Events generated will have this number tagged with them.
  363.  *   Returns various negative numbers on error conditions.
  364.  *
  365.  *   if adddom is nonzero, add default domain
  366.  */
  367. static longword
  368. Sdomain(mname, adddom, nameserver, timedout)
  369.     byte *mname;
  370.     int adddom;
  371.     longword nameserver;
  372.     int *timedout;            /* Set to 1 on timeout */
  373. /* Sdomain */ {
  374. #define NAMBUFSIZ 512
  375.     byte namebuff[NAMBUFSIZ];
  376.     int namlen;
  377.     register int i;
  378.     register byte *p;
  379.     byte *nextdomain(byte *, int);
  380.     longword response;
  381.  
  382.     response = 0;
  383.     *timedout = 1;            /* presume a timeout */
  384.  
  385.     if (nameserver == 0L)
  386.         {            /* no nameserver, give up now */
  387.         outs("\r\n No nameserver defined!");
  388.         return (0);
  389.         }
  390.  
  391.     while (*mname == ' ' || *mname == '\t') mname++;
  392.                         /* kill leading spaces */
  393.     if (*mname == '\0')        /* no host name, fail */
  394.         return (0L);
  395.  
  396.     qinit();            /* initialize some flag fields */
  397.  
  398.     namlen = strlen(mname);        /* Get length of name */
  399.     if (namlen >= NAMBUFSIZ || namlen == 0)    /* Check it before copying */
  400.         return (0L);
  401.  
  402.     strcpy(namebuff, mname);            /* OK to copy */
  403.     if(namebuff[strlen(namebuff) - 1] == '.')
  404.         namebuff[strlen(namebuff) - 1] = '\0';
  405.  
  406.     if (adddom > 0 && adddom <= countpaths(def_domain))
  407.         {                 /* there is a search list */
  408.         p = getpath(def_domain, adddom); /* get end of def_domain */
  409.         if (p != NULL)            /* if got something */
  410.             {
  411.             if (strlen(p) > (NAMBUFSIZ - namlen - 1))
  412.                 return (0L);        /* if too big */
  413.             if (*p != '.')            /* one dot please */
  414.                 strcat(namebuff, ".");
  415.             strcat(namebuff, p);    /* new name to try */
  416.             }
  417.             }
  418.  
  419.     outs("\r\n  trying name "); outs(namebuff); /* hand holder */
  420.     /*
  421.      * This is not terribly good, but it attempts to use a binary
  422.      * exponentially increasing delays.
  423.      */
  424.     for (i = 2; i < 17; i *= 2)
  425.         {
  426.         if (sendom(namebuff, nameserver, 0xf001) == 0)    /* try UDP */
  427.             goto sock_err;        /* sendom() failed */
  428.         ip_timer_init(dom_sock, i);
  429.         do
  430.             {
  431.             if (tcp_tick(dom_sock) == 0) /* read packets */
  432.                 goto sock_err;    /* socket is closed */
  433.             if (ip_timer_expired(dom_sock)) break;
  434.             if (sock_dataready(dom_sock)) *timedout = 0;
  435.             } while (*timedout);
  436.  
  437.         if (*timedout == 0) break;    /* got an answer */
  438.         }
  439.  
  440.     if (*timedout == 0)            /* if answer, else fall thru*/
  441.         {
  442.         response = udpdom();        /* process the received data*/
  443.         sock_close(dom_sock);
  444.         return (response);
  445.         }
  446.  
  447. sock_err:
  448.     outs("\r\n  Cannot reach name server ");
  449.     ntoa(namebuff, nameserver);    /* nameserver IP to dotted decimal */
  450.     outs(namebuff);            /* display nameserver's IP */
  451.     *timedout = 1;            /* say timeout */
  452.     sock_close(dom_sock);        /* do for safety's sake */
  453.     return (0);
  454. }
  455.  
  456. /*
  457.  * nextdomain - given domain and count = 0,1,2,..., return next larger
  458.  *        domain or NULL when no more are available
  459.  */
  460. static byte *
  461. nextdomain(byte *domain, int count)
  462. {
  463.     register byte *p;
  464.     register int i;
  465.  
  466.     if ((p = domain) == NULL) return (NULL);    /* failure */
  467.     if (count < 0) return (NULL);
  468.  
  469.     for (i = 0; i < count; i++)
  470.         {
  471.         p = strchr(p, '.');
  472.         if (p == NULL) return (NULL);
  473.         p++;
  474.         }
  475.     return (p);
  476. }
  477.  
  478. static longword
  479. resolve2(byte *name)
  480. {            /* detailed worker for resolve() */
  481.     longword ip_address;
  482.     register int count;
  483.     register int i, j;
  484.     byte timeout[MAX_NAMESERVERS];
  485.     struct useek qp;            /* temp buffer */
  486.     udp_Socket ds;                  /* working socket (big!) */
  487.  
  488.     question = &qp;
  489.     dom_sock = &ds;
  490.     count = 0;
  491.     memset(timeout, 0, sizeof(timeout));
  492.  
  493.     for (;;)    
  494.         {
  495.         for (i = 0; i < last_nameserver; i++)
  496.             if (timeout[i] == 0)
  497.                 if (ip_address = Sdomain(name, count,
  498.                     def_nameservers[i], &timeout[i]))
  499.                         return (ip_address);
  500.  
  501.         if ((loc_domain = nextdomain(def_domain, count++)) == NULL)
  502.             return (0);    /* nothing else to try */
  503.         }
  504.     return (0);
  505. }
  506.  
  507.  
  508. /*
  509.  * resolve()
  510.  *     convert domain name -> address resolution.
  511.  *     returns 0 if name is unresolvable right now
  512.  */
  513.  
  514. longword 
  515. resolve(name) byte *name; {
  516.     if (name == NULL) return (0L);
  517.  
  518.     rip(name);            /* terminate on cr and lf's */
  519.     if (isaddr(name) != 0)
  520.         return (aton(name));    /* IP numerical address */
  521.     return (resolve2(name));    /* call upon the worker */
  522. }
  523.  
  524. /*
  525.  * aton()
  526.  *    - converts [a.b.c.d] or a.b.c.d to 32 bit long
  527.  *    - returns 0 on error (safer than -1)
  528.  */
  529.  
  530. longword 
  531. aton(text)
  532. byte *text;
  533. {
  534.     register int i;
  535.     longword ip, j;
  536.  
  537.     ip = 0;
  538.     if (text == NULL) return (0L);        /* failure */
  539.  
  540.     if (*text == '[')
  541.         text++;
  542.     for (i = 24; i >= 0; i -= 8)
  543.         {
  544.         j = atoi(text) & 0xff;
  545.         ip |= (j << i);
  546.         while (*text != '\0' && *text != '.') text++;
  547.         if (*text == '\0')
  548.             break;
  549.         text++;
  550.         }
  551.     return (ip);
  552. }
  553.  
  554. /*
  555.  * isaddr
  556.  *    - returns nonzero if text is simply ip address
  557.  * such as 123.456.789.012 or [same] or 123 456 789 012 or [same]
  558.  */
  559. int 
  560. isaddr(text)
  561. byte *text;
  562. {
  563.     register byte ch;
  564.  
  565.     if (text == NULL) return (0);        /* failure */
  566.     while (ch = *text++)
  567.         {
  568.         if (('0' <= ch) && (ch <= '9'))
  569.             continue;    /* in digits */
  570.         if ((ch == '.') || (ch == ' ') || (ch == '[') || (ch == ']'))
  571.                 continue;            /* and in punct */
  572.         return (0);                /* failure */
  573.         }
  574.     return (1);
  575. }
  576.  
  577.